function dataType(a){
    return Object.prototype.toString.call(a).match(/\s([^\]]+)/)[1]
}

class IDB{
    constructor(name, v, option){
        if(!name){
            throw new Error('必须提供数据库名称')
        }
        this.name = name;
        this.DB = null;
        
        let opt = option || {};
        let DBV = undefined;
        this._hub = [];

        if(typeof v === 'object'){
            opt = v
        }else if(typeof v === 'number'){
            DBV = v
        }
        
        let {
            store
        } = opt
        
        this.DBRequest = window.indexedDB.open(this.name, DBV);

        this.DBRequest.onupgradeneeded = event => {
            this.DB = this.DBRequest.result;

            /**
             * @param {Object} store
             * @param {Object} store.option -- createObjectStore第二个参数
             * @param {Array.<Array>} store.indexs -- 索引
             * @example 
             * {
             *   option:{autoIncrement: true}
             *   indexs:[
             *      ['name','name',{unique: false}],
             *      ['age','year']
             *      ['email']
             *   ]
             * }
            */
            if(store){
                if (!this.DB.objectStoreNames.contains(this.name)) {
                    const objectStore = this.DB.createObjectStore(this.name, store.option || { autoIncrement: true });
                    console.log(store.indexs)
                    if(store.indexs){
                        store.indexs.forEach( item => {
                            objectStore.createIndex(
                                item[0], 
                                item[1] || item[0], 
                                item[2] || (typeof item[1]==='object')? item[1] :{ 
                                    unique: false
                                }
                            );
                        })
                    }
                }
            }
            
            this._emit('upgradeneeded', event)
        }
        this.DBRequest.onsuccess = event => {
            this.DB = this.DBRequest.result;
            this._emit('success', event)
        }
        this.DBRequest.onerror = function(event) {
            this._emit('error', event)
        }
    }

    _emit(event, data) {
        (this._hub[event] || []).forEach(handler => {
            try{
                handler(data)
            }catch(e){
                console.error(e)
            }
        });
    }

    _on(event, handler) {
        if (!this._hub[event]) this._hub[event] = [];
        this._hub[event].push(handler);
    }

    _success(cb){
        return new Promise(resolve=>{
            if(this.DB){
                cb && cb()
                resolve()
            }else{
                this._on('success', cb || function(){})
                resolve()
            }
        })
    }

    add(data){
        this._success(()=>{
            const transaction = this.DB.transaction([this.name], 'readwrite');
            const objectStore = transaction.objectStore(this.name);
         
            if(dataType(data) === 'Array'){
                data.forEach(item=>{
                    objectStore.add(item);
                })
            }else{
                objectStore.add(data);
            }
        })
    }

    delete(key){
        return new Promise((resolve,reject) => {
            this._success(()=>{
                const transaction = this.DB.transaction([this.name], 'readwrite');
                const objectStore = transaction.objectStore(this.name);
                const request = objectStore.delete(key);
                request.onsuccess= event => {
                    resolve(event)
                }
                request.onerror= event => {
                    reject(event)
                }
            })
        })
    }

    searchByIndex(index, value) {
        return new Promise((resolve,reject)=>{
            this._success(()=>{
                const transaction = this.DB.transaction([this.name], 'readonly');
                const store = transaction.objectStore(this.name);
                const storeIndex = store.index(index);
                const request = storeIndex.getAll(value);
                request.onerror = function (event) {
                    console.log('检索失败');
                    reject(event)
                };
        
                request.onsuccess = function (event) {
                    if (request.result) {
                        resolve(request.result)
                    } else {
                        resolve([])
                    }
                };
            })
        })
    }

    get(id) {
        return new Promise((resolve,reject)=>{
            this._success(()=>{
                const transaction = this.DB.transaction([this.name], 'readonly');
                const store = transaction.objectStore(this.name);
                const request = store.get(id)
                request.onerror = function (event) {
                    console.log('检索失败');
                    reject(event)
                };
        
                request.onsuccess = function (event) {
                    if (request.result) {
                        resolve(request.result)
                    } else {
                        resolve([])
                    }
                };
            })
        })
    }

    // range 'size>4 | num'
    async getCursor(range,sort) {
        function fomateRange(range){
            function TB(t){
                return !(/\=/.test(t))
            }
            function TN(s,m){
                return s && m==='num'?parseFloat(s):s
            }
            
            let keyRange
            let key = ''
            if(typeof range === 'string'){
                let mode = range.split(' | ')[1];
                let symbols = range.match(/[\=<>&]+/g);
                let sl = range.split(/[\=<>&]+/g)
                let a = TN(sl[1],mode),
                    b = TN(sl[3],mode);
                key = sl[0];
                console.log(typeof a)
                if(symbols.length === 3){
                    keyRange = IDBKeyRange.bound(a, b, TB(symbols[0]), TB(symbols[2]))
                }else if(symbols.length === 1){
                    switch(symbols[0]){
                        case '<=':
                            keyRange = IDBKeyRange.upperBound(a);
                            break;
                        case '<':
                            keyRange = IDBKeyRange.upperBound(a, true);
                            break;
                        case '>=':
                            keyRange = IDBKeyRange.lowerBound(a);
                            break;
                        case '>':
                            keyRange = IDBKeyRange.lowerBound(a, true);
                            break;
                        case '===':
                            keyRange = IDBKeyRange.only(a);
                            break;
                    }
                }else{
                    console.error('无效的<range>')
                }
            }else{
                console.error('无效的<range>')
                return null
            }
            return [key,keyRange]
        }

        
        // await this._success()
        // const transaction = this.DB.transaction([this.name], 'readonly');
        // const store = transaction.objectStore(this.name);
        // let request = null;
        // if(range){
        //     const [key,keyRange] = fomateRange(range);
        //     const dbindex = store.index(key)
        //     request = dbindex.openCursor(keyRange, sort || 'next');
        // }else{
        //     request = store.openCursor()
        // }

        // return new Promise((resolve,reject)=>{
        //     request.onerror = function (event) {
        //         console.log('检索失败');
        //         reject(event)
        //     };
    
        //     let res=[]
        //     request.onsuccess = function (event) {
        //         const cursor=event.target.result
        //         if (cursor) {
        //             res.push(cursor.value)
        //             cursor.continue();
        //         } else {
        //             resolve(res)
        //         }
        //     };
        // })
        
        
        await this._success()
        const transaction = this.DB.transaction([this.name], 'readonly');
        const store = transaction.objectStore(this.name);
        let request = null;
        if(range){
            const [key,keyRange] = fomateRange(range);
            const dbindex = store.index(key)
            request = dbindex.openCursor(keyRange, sort || 'next');
        }else{
            request = store.openCursor()
        }
        
        return request
        // return new Promise((resolve,reject)=>{
        //     request.onerror = function (event) {
        //         console.log('检索失败');
        //         reject(event)
        //     };
    
        //     let res=[]
        //     request.onsuccess = function (event) {
        //         const cursor=event.target.result
        //         console.log('go')
        //         resolve(cursor)
        //     };
        // })
    }

    searchAll() {
        return new Promise((resolve,reject)=>{
            this._success(()=>{
                const transaction = this.DB.transaction([this.name], 'readonly');
                const store = transaction.objectStore(this.name);
                const request = store.getAll()
                request.onerror = function (event) {
                    console.log('检索失败');
                    reject(event)
                };
        
                request.onsuccess = function (event) {
                    if (request.result) {
                        resolve(request.result)
                    } else {
                        resolve([])
                    }
                };
            })
        })
    }
}